/*
 * Copyright 2010 Christoph Widulle (christoph.widulle@googlemail.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS"
 * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */


package com.android1.amarena2d.nodes.behavior.delegates;

import com.android1.amarena2d.actions.base.Action;
import com.android1.amarena2d.actions.movement.*;
import com.android1.amarena2d.commons.Callback;
import com.android1.amarena2d.engine.EngineObject;
import com.android1.amarena2d.engine.TargetActionsStore;
import com.android1.amarena2d.nodes.behavior.ActionTarget;


public class DynamicsDelegateImpl extends EngineObject implements DynamicsDelegate, DynamicsDelegate.MoveWidthOptions, DynamicsDelegate.MoveOptions {

    private final TargetActionsStore targetActionsStore;

    private Action lastAction;

    private final MoveTo moveTo = new MoveTo(0, 0, 0);
    private final MoveBy moveBy = new MoveBy(0, 0, 0);
    private final Move move = new Move(0, 0);
    private final AccelerateMove accelerateMove = new AccelerateMove(move, 0, 0, 0);
    private final TerminalAccelerateMove terminalAccelerateMove = new TerminalAccelerateMove(move, 0, 0, 0, 0);

    public DynamicsDelegateImpl(ActionTarget parent) {
        this.targetActionsStore = engine.getActionManager().register(parent);
    }

    @Override
    public MoveOptions to(float x, float y, float duration) {
        moveTo.reset(x, y, duration);
        if (!moveTo.isRunning())
            fire(moveTo);
        return this;
    }

    @Override
    public MoveOptions by(float x, float y, float duration) {
        moveBy.reset(x, y, duration);
        if (!moveBy.isRunning())
            fire(moveBy);
        return this;
    }

    @Override
    public MoveWidthOptions with(float velocityX, float velocityY) {
        move.reset(velocityX, velocityY);
        if (!move.isRunning())
            fire(move);
        return this;
    }

    @Override
    public void stop() {
        if (lastAction != null) {
            targetActionsStore.stop(lastAction);
            if (terminalAccelerateMove.isRunning())
                targetActionsStore.stop(terminalAccelerateMove);
            if (accelerateMove.isRunning())
                targetActionsStore.stop(accelerateMove);

            lastAction = null;
        }
    }

    @Override
    public MoveOptions accelerate(float accelerateX, float accelerateY, float duration) {
        assert (move.isRunning()) : "Can only accelerate a running move-with action.";
        if (terminalAccelerateMove.isRunning())
            targetActionsStore.stop(terminalAccelerateMove);
        accelerateMove.reset(move, accelerateX, accelerateY, duration);
        targetActionsStore.run(accelerateMove);
        return this;
    }

    @Override
    public MoveOptions accelerate(float accelerateX, float accelerateY, float terminalVelocityX, float terminalVelocityY) {
        assert (move.isRunning()) : "Can only accelerate a running move-with action.";
        if (accelerateMove.isRunning())
            targetActionsStore.stop(accelerateMove);
        terminalAccelerateMove.reset(move, accelerateX, accelerateY, terminalVelocityX, terminalVelocityY);
        targetActionsStore.run(terminalAccelerateMove);
        return this;
    }

    @Override
    public void setOnFinished(Callback<ActionTarget> callback) {
        lastAction.setOnStopCallback(callback);
    }

    private void fire(Action action) {
        if (lastAction != null && lastAction != action)
            targetActionsStore.stop(lastAction);
        lastAction = action;
        targetActionsStore.run(action);
    }


}
